package com.lemon.exam.service.impl;

import com.lemon.exam.common.crud.BaseServiceImpl;
import com.lemon.exam.entity.dto.RoleMenuResourceDTO;
import com.lemon.exam.entity.po.RoleMenuResourcePO;
import com.lemon.exam.repository.RoleMenuResourceRepository;
import com.lemon.exam.service.IRoleMenuResourceService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 菜单-接口中间表 服务实现类
 *
 * @author Lemon
 * @since 2025/05/08 12:31:56
 */
@Slf4j
@Service
public class RoleMenuResourceServiceImpl extends BaseServiceImpl<RoleMenuResourcePO, Long, RoleMenuResourceRepository> implements IRoleMenuResourceService {
    @Override
    public Mono<Map<Long, List<String>>> findByRoleId(Long roleId) {
        return repository.findByRoleId(roleId).collect(Collectors.groupingBy(
                        RoleMenuResourcePO::getMenuId,
                        Collectors.mapping(RoleMenuResourcePO::getResourcePath, Collectors.toList())
                ))
                .defaultIfEmpty(Collections.emptyMap());
    }

    @Override
    public Mono<Boolean> insert(List<RoleMenuResourceDTO> roleMenuResourceList) {
        return Flux.fromIterable(roleMenuResourceList)
                .map(DTO_CONVERTER_PO)
                .concatMap(repository::save)
                .then(Mono.just(true));
    }

    /**
     * DTO 转 PO
     */
    @NotNull
    private static final Function<RoleMenuResourceDTO, RoleMenuResourcePO> DTO_CONVERTER_PO = item -> {
        RoleMenuResourcePO po = new RoleMenuResourcePO();
        po.setRoleId(item.getRoleId());
        po.setMenuId(item.getMenuId());
        if (StringUtils.hasText(item.getResourcePath())) {
            po.setResourcePath(item.getResourcePath());
        }
        return po;
    };

    @Override
    public Mono<Boolean> delete(List<RoleMenuResourceDTO> roleMenuResourceList) {
        return Flux.fromIterable(roleMenuResourceList)
                .map(DTO_CONVERTER_CRITERIA)
                .map(Query::query)
                .concatMap(item -> template.delete(item, RoleMenuResourcePO.class).then())
                .then(Mono.just(true));
    }

    /**
     * DTO 转 Criteria
     */
    private static final Function<RoleMenuResourceDTO, Criteria> DTO_CONVERTER_CRITERIA = dto -> {
        Criteria criteria = Criteria.where("role_id").is(dto.getRoleId()).and("menu_id").is(dto.getMenuId());
        return StringUtils.hasText(dto.getResourcePath()) ?
                criteria.and("resource_path").is(dto.getResourcePath()) :
                criteria.and("resource_path").isNull();

    };
}
